#include "task.h"
#include "util.h"
#include "ds_conf.h"
#include "storage.h"
#include "globals.h"

bool DSTask::Init(CliConn *cli_conn, struct evbuffer *buf, int buf_size) {
  if (cli_conn_ != NULL)
    return false;

  if (cli_conn == NULL)
    return false;

  if (in_buf_ == NULL) {
    if ((in_buf_ = evbuffer_new()) == NULL)
      return false;
  }

  if (out_buf_ == NULL) {
    if ((out_buf_ = evbuffer_new()) == NULL)
      return false;
  }

  evbuffer_remove(buf, &in_header_, sizeof(TrackerHeader));
  evbuffer_remove_buffer(buf, in_buf_, buf_size - sizeof(TrackerHeader));

  cli_conn_ = cli_conn;
  return true;
}

void DSTask::Destroy() {
  if (in_buf_) {
    evbuffer_free(in_buf_);
    in_buf_ = NULL;
  }

  if (out_buf_) {
    evbuffer_free(out_buf_);
    out_buf_ = NULL;
  }
}

void DSTask::Perform() {
  assert(in_buf_);
  int64_t in_buf_size = evbuffer_get_length(in_buf_);

  int64_t pkg_len = Util::buff2long(in_header_.pkg_len);
  if (pkg_len < 0 || in_buf_size < pkg_len)
    return;

  switch (in_header_.cmd) {
  case STORAGE_PROTO_CMD_UPLOAD_FILE:
    UploadFile();
    break;

  default:
    LOG_ERROR("DSTask::Perform unknown cmd %d", in_header_.cmd);
    break;
  }
}

void DSTask::PerformDefferCb(DKBaseThread *thread, void *arg) {
  DSTask *task = (DSTask *)arg;
  if (task)
    task->Perform();
}

bool DSTask::UploadFile() {
  int64_t up_info_size =
      1 + FDFS_PROTO_PKG_LEN_SIZE + FDFS_FILE_EXT_NAME_MAX_LEN;

  int64_t in_buf_size = evbuffer_get_length(in_buf_);

  if (in_buf_size < up_info_size) {
    LOG_ERROR("upload file body size  %d is too small");
    return false;
  }

  char *p = (char *)evbuffer_pullup(in_buf_, up_info_size); 
  int store_path_index = *p++;
  
  if (store_path_index == -1) {
    store_path_index =
        (g_storage->store_path_index)%g_conf->data_path_count;
    g_storage->store_path_index = store_path_index + 1;
  }
  else if (store_path_index < 0 ||
           store_path_index >= g_conf->data_path_count) {
    LOG_ERROR("store_path_index:%d out of range", store_path_index);
    return false;
  }

  int64_t file_bytes = Util::buff2long(p);
  p += FDFS_PROTO_PKG_LEN_SIZE;
 
  if (file_bytes < 0 || file_bytes != in_buf_size - up_info_size) {
    LOG_ERROR("file bytes:"INT64_PRINTF_FORMAT \
              "incorrect, body size:"INT64_PRINTF_FORMAT,
              file_bytes, in_buf_size);
    return false;
  }

  char file_ext_name[FDFS_FILE_EXT_NAME_MAX_LEN+1];
  memcpy(file_ext_name, p, FDFS_FILE_EXT_NAME_MAX_LEN); 
  file_ext_name[FDFS_FILE_EXT_NAME_MAX_LEN] = '\0';
  
  evbuffer_drain(in_buf_, up_info_size);
}
